package org.xteam.camllight;

public class HashUnivParam implements Primitive {
	
	private static class HashState {
		
		private static final int Alpha = 65599;
		private static final int Beta = 19;
		
		int hash_univ_limit;
		int hash_univ_count;
		int hash_accu = 0;
		
		public HashState(int limit, int count) {
			this.hash_univ_limit = limit;
			this.hash_univ_count = count;
		}

		public void hash(Object object) {
			hash_univ_limit--;
			if (hash_univ_count < 0 || hash_univ_limit < 0)
				return;
			
			if (object instanceof Integer) {
				hash_univ_count--;
			    Combine(Value.longVal((Integer)object));
			    return;
			}
			if (object instanceof Atom) {
				int tag = ((Atom)object).tag();
				hash_univ_count--;
				Combine_small(tag);
				return;
			}
			if (object instanceof String) {
				hash_univ_count--;
				String str = (String) object;
				for (int i = 0; i < str.length(); ++i) {
			        Combine_small(str.charAt(i));
				}
				return;
			}
			throw new RuntimeException("not completed");
		}

		private void Combine_small(int value) {
			hash_accu = hash_accu * Beta + value;
		}

		private void Combine(int value) {
			hash_accu = hash_accu * Alpha + value;
		}
	}

	public Object exec(Object... args) {
		HashState state = new HashState(Value.longVal((Integer)args[1]), Value.longVal((Integer)args[0]));
		state.hash(args[2]);
		return Value.valLong(state.hash_accu & 0x3FFFFFFF);
	}

}
